Developing a computer program is often a very large and cumbersome task. For any relatively large project, there is a significant amount of coding that needs to be done, followed by testing and debugging. This typically leads to frequent changes, new enhancements and so forth, which may fix many errors but also may introduce new errors.
For example, consider a program written in JavaScript® or similar loosely-typed programming language. Programming languages that are loosely typed have variables that are declared without a type; the programming language determines the type for each declared variable and there is no internal type checking performed. Further, types are dynamic, e.g., a variable x may be set to a numerical value (var x=10, whereby variable x's type is a number) and later, possibly in the very next statement, the same variable x may be set to a string (var x=“Tuesday”, whereby variable x's type is now a string). These characteristics of JavaScript® can lead to a number of errors. For example, an existing function may expect a string as a parameter when invoked by a new calling function, but that new calling function may instead provide a number, causing a bug.
Code written in dynamic languages, such as JavaScript® code, can be harder to maintain and debug due to their dynamic runtime behavior. Function parameters, return values, and property accessors are typically not type-enforced resulting in a large amount of code that needs to handle any object type at any time. It is common for JavaScript® code to have a large amount of checks inside of a function to ensure that the parameters are of the correct type and/or shape. Additionally, the results of functions are typically checked before using them due to this same dynamic nature. To make these checks, robust JavaScript® code nearly always litters ‘if’ checks to validate the incoming and outgoing data. Without the checks, it is easy to misuse the code and do unexpected things (something may not fail right away, leading to issues further down the road). These checks clutter the code and negatively impact performance.
To debug such errors, a developer often refers to documentation. The most common approach in software development is to place the documentation (e.g., for functions/classes JavaScript® prototypes) within the source code as comments or the like. However, this makes the source code hard to follow, as proper documentation is verbose and typically requires more lines than the actual code. This mixture of source code and its documentation is also difficult for humans to read without extensive post-processing and tooling.